package com.yswee.framework.widget.swipemenu;

import com.yswee.framework.utils.UnitUtils;
import com.yswee.framework.widget.layoutview.ILayoutView;
import com.yswee.framework.widget.layoutview.MFrameLayout;

import androidx.core.view.GestureDetectorCompat;
import androidx.core.widget.ScrollerCompat;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.AbsListView;

public class SwipeMenuLayout<T> extends MFrameLayout<T> {

	private static final int STATE_CLOSE = 0;
	private static final int STATE_OPEN = 1;

	private int mSwipeDirection;

	private View mContentView;
	private View mMenuView;
	private int mDownX;
	private int state = STATE_CLOSE;
	private GestureDetectorCompat mGestureDetector;
	private OnGestureListener mGestureListener;
	private boolean isFling;
	private int MIN_FLING;
	private int MAX_VELOCITYX;
	private ScrollerCompat mOpenScroller;
	private ScrollerCompat mCloseScroller;
	private int mBaseX;
	private Interpolator mCloseInterpolator;
	private Interpolator mOpenInterpolator;
	private boolean mSwipeEnabled;
	
	public void setSwipeDirection(int swipeDirection) {
		mSwipeDirection = swipeDirection;
	}

	public SwipeMenuLayout(View contentView, View menuView) {
		this(contentView, menuView, null, null);
	}

	public SwipeMenuLayout(View contentView, View menuView,
			Interpolator closeInterpolator, Interpolator openInterpolator) {
		super(((View) contentView).getContext());
		MIN_FLING = UnitUtils.dip2pix(mContext, 15);
		MAX_VELOCITYX = - UnitUtils.dip2pix(mContext, 500);
		mCloseInterpolator = closeInterpolator;
		mOpenInterpolator = openInterpolator;
		mContentView = contentView;
		mMenuView = menuView;
		initializeMenuLayout();
	}

	protected void initializeMenuLayout() {
		setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.WRAP_CONTENT));
		mGestureListener = new SimpleOnGestureListener() {
			@Override
			public boolean onDown(MotionEvent e) {
				isFling = false;
				return true;
			}

			@Override
			public boolean onFling(MotionEvent e1, MotionEvent e2,
					float velocityX, float velocityY) {
				if (Math.abs(e1.getX() - e2.getX()) > MIN_FLING
						&& velocityX < MAX_VELOCITYX) {
					isFling = true;
				}
				return super.onFling(e1, e2, velocityX, velocityY);
			}
		};
		mGestureDetector = new GestureDetectorCompat(getContext(),
				mGestureListener);

		// mScroller = ScrollerCompat.create(getContext(), new
		// BounceInterpolator());
		if (mCloseInterpolator != null) {
			mCloseScroller = ScrollerCompat.create(getContext(),
					mCloseInterpolator);
		} else {
			mCloseScroller = ScrollerCompat.create(getContext());
		}
		if (mOpenInterpolator != null) {
			mOpenScroller = ScrollerCompat.create(getContext(),
					mOpenInterpolator);
		} else {
			mOpenScroller = ScrollerCompat.create(getContext());
		}

		LayoutParams contentParam = null;
		if (mContentView.getLayoutParams() != null) {
			contentParam = (LayoutParams) mContentView.getLayoutParams();
		} else {
			contentParam = new LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		}
		addView(mContentView, contentParam);
		LayoutParams menuParam = null;
		if (mMenuView.getLayoutParams() != null) {
			menuParam = (LayoutParams) mMenuView.getLayoutParams();
		} else {
			menuParam = new LayoutParams(
					LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
		}
		addView(mMenuView, menuParam);

		// if (mContentView.getBackground() == null) {
		// mContentView.setBackgroundColor(Color.WHITE);
		// }

		// in android 2.x, MenuView height is MATCH_PARENT is not work.
		// getViewTreeObserver().addOnGlobalLayoutListener(
		// new OnGlobalLayoutListener() {
		// @Override
		// public void onGlobalLayout() {
		// setMenuHeight(mContentView.getHeight());
		// // getViewTreeObserver()
		// // .removeGlobalOnLayoutListener(this);
		// }
		// });

	}

	@Override
	protected void onAttachedToWindow() {
		super.onAttachedToWindow();
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
	}

	public boolean onSwipe(MotionEvent event) {
		mGestureDetector.onTouchEvent(event);
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mDownX = (int) event.getX();
			isFling = false;
			break;
		case MotionEvent.ACTION_MOVE:
			// Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX());
			int dis = (int) (mDownX - event.getX());
			if (state == STATE_OPEN) {
				dis += mMenuView.getWidth()*mSwipeDirection;;
			}
			swipe(dis);
			break;
		case MotionEvent.ACTION_UP:
			if ((isFling || Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 2)) &&
					Math.signum(mDownX - event.getX()) == mSwipeDirection) {
				// open
				smoothOpenMenu();
			} else {
				// close
				smoothCloseMenu();
				return false;
			}
			break;
		}
		return true;
	}

	public boolean isOpen() {
		return state == STATE_OPEN;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return super.onTouchEvent(event);
	}

	private void swipe(int dis) {
		if (!mSwipeEnabled) {
			return;
		}
		if (Math.signum(dis) != mSwipeDirection) {
			dis = 0;
		} else if (Math.abs(dis) > mMenuView.getWidth()) {
			dis = mMenuView.getWidth() * mSwipeDirection;
		}

		LayoutParams contentParam = (LayoutParams) mContentView.getLayoutParams();
		mContentView.layout(contentParam.leftMargin - dis, mContentView.getTop(),
				contentParam.leftMargin + mContentView.getWidth() -dis, getMeasuredHeight());

		LayoutParams menuParam = (LayoutParams) mMenuView.getLayoutParams();
		if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {
			int leftMargin = menuParam.leftMargin;
			int topMargin = menuParam.topMargin;
			if (dis <= 0) {
				leftMargin = 0;
			}
			mMenuView.layout(mContentView.getWidth() + leftMargin - dis, 
					mMenuView.getTop() + topMargin,
					mContentView.getWidth()+ leftMargin + mMenuView.getWidth() - dis,
					mMenuView.getTop() + topMargin + mMenuView.getHeight());
		} else {
			int rightMargin = menuParam.rightMargin;
			int topMargin = menuParam.topMargin;
			if (dis >= 0) {
				rightMargin = 0;
			}
			mMenuView.layout(-mMenuView.getWidth() + rightMargin - dis, 
					mMenuView.getTop() + topMargin,
					rightMargin - dis, 
					mMenuView.getTop() + topMargin + mMenuView.getHeight());
		}
	}

	@Override
	public void computeScroll() {
		if (state == STATE_OPEN) {
			if (mOpenScroller.computeScrollOffset()) {
				swipe(mOpenScroller.getCurrX()*mSwipeDirection);
				postInvalidate();
			}
		} else {
			if (mCloseScroller.computeScrollOffset()) {
				swipe((mBaseX - mCloseScroller.getCurrX())*mSwipeDirection);
				postInvalidate();
			}
		}
	}

	public void smoothCloseMenu() {
		state = STATE_CLOSE;
		if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {
			mBaseX = -mContentView.getLeft();
			mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350);
		} else {
			mBaseX = mMenuView.getRight();
			mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350);
		}
		postInvalidate();
	}

	public void smoothOpenMenu() {
		if (!mSwipeEnabled) {
			return;
		}
		state = STATE_OPEN;
		if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {
			mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350);
		} else {
			mOpenScroller.startScroll(mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350);
		}
		postInvalidate();
	}

	public void closeMenu() {
		if (mCloseScroller.computeScrollOffset()) {
			mCloseScroller.abortAnimation();
		}
		if (state == STATE_OPEN) {
			state = STATE_CLOSE;
			swipe(0);
		}
	}

	public void openMenu() {
		if (!mSwipeEnabled) {
			return;
		}
		if (state == STATE_CLOSE) {
			state = STATE_OPEN;
			swipe(mMenuView.getWidth() * mSwipeDirection);
		}
	}

	public View getContentView() {
		return mContentView;
	}

	public View getMenuView() {
		return mMenuView;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mMenuView.measure(MeasureSpec.makeMeasureSpec(0,
				MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(
				getMeasuredHeight(), MeasureSpec.EXACTLY));
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		mContentView.layout(0, 0, getMeasuredWidth(),
				mContentView.getMeasuredHeight());
		if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) {
			mMenuView.layout(getMeasuredWidth(), 0,
					getMeasuredWidth() + mMenuView.getMeasuredWidth(),
					mContentView.getMeasuredHeight());
		} else {
			mMenuView.layout(-mMenuView.getMeasuredWidth(), 0,
					0, mContentView.getMeasuredHeight());
		}
	}

	public void setMenuHeight(int measuredHeight) {
		LayoutParams params = (LayoutParams) mMenuView.getLayoutParams();
		if (params.height != measuredHeight) {
			params.height = measuredHeight;
			mMenuView.setLayoutParams(mMenuView.getLayoutParams());
		}
	}

	public void setSwipeEnabled(boolean swipEnable){
		mSwipeEnabled = swipEnable;
	}

	public boolean getSwipeEnabled(){
		return mSwipeEnabled;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void setPosition(int totalcount, int position) {
		super.setPosition(totalcount, position);
		((ILayoutView<T>) mContentView).setPosition(totalcount, position);
		((ILayoutView<T>) mMenuView).setPosition(totalcount, position);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void notifyDataSetChanged() {
		super.notifyDataSetChanged();
		((ILayoutView<T>) mContentView).notifyDataSetChanged();
		((ILayoutView<T>) mMenuView).notifyDataSetChanged();
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void onApplyData() {
		if (mContentView instanceof ILayoutView<?>) {
			((ILayoutView<T>) mContentView).setDataSource(mDataItem);
		}
		if (mMenuView instanceof ILayoutView<?>) {
			((ILayoutView<T>) mMenuView).setDataSource(mDataItem);
		}
	}
}
